package org.jpropelleralt.ledger.list;

import org.jpropelleralt.box.Box;
import org.jpropelleralt.change.Change;
import org.jpropelleralt.ledger.Ledger;

/**
 * Provides data for a record of a {@link Ledger}, by transforming
 * objects of a given type T.
 * 
 * Also implements {@link Box}, and changes with a shallow {@link Change}
 * whenever the {@link RecordTransformer} might produce different
 * results for the same input - usually if it changes the fields,
 * for example the number, names or classes of fields.
 * 
 * @param <T>		The type of objects to be transformed to records
 */
public interface RecordTransformer<T> extends Box {

	/**
	 * Check whether the data in a specific record and field is editable.
	 * @param record	The record index, >=0 and < {@link #recordCount()}
	 * @param recordObject	The actual object for this record
	 * @param field		The field index, >=0 and < {@link #fieldCount()} 
	 * @return	True if data is editable
	 */
	public boolean editable(int record, T recordObject, int field);

	/**
	 * Get the data in a specific record and field.
	 * @param record		The record index, >=0 and < {@link #recordCount()}
	 * @param recordObject	The actual object for this record
	 * @param field			The field index, >=0 and < {@link #fieldCount()} 
	 * @return	Data
	 */
	public Object get(int record, T recordObject, int field);

	/**
	 * Set the data in a specific record and field.
	 * @param record		The record index, >=0 and < {@link #recordCount()}
	 * @param recordObject	The actual object for this record
	 * @param field			The field index, >=0 and < {@link #fieldCount()} 
	 * @param value			The data value to set
	 */
	public void set(int record, T recordObject, int field, Object value);
	
    /**
     * Returns the name of a specific field of each record.
     *
	 * @param field		The field index, >=0 and < {@link #fieldCount()} 
     * @return the name of the field
     */
    public String fieldName(int field);

    /**
     * Returns the {@link Class} of a specific field of each record.
     * 
     * Implementations must ensure that all values returned by
     * {@link #get(int, int)} using the same field index are
     * of this class or a subclass/subinterface.
     *
	 * @param field		The field index, >=0 and < {@link #fieldCount()} 
     * @return the {@link Class} of the field
     */
    public Class<?> fieldClass(int field);
	
	/**
	 * The number of fields in each record
	 * @return	Current field count.
	 */
	public int fieldCount();
	
}
